<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue监测数据改变的原理</title>
    <script src="../js/vue-2.6.12开发.js"></script>
</head>

<body>
    <!-- 
Vue监视数据的原理:
    1.Vue会监视data中的所有层次的数据

    2.如何监视对象中的数据？
               通过setter实现监视 且要在new Vue时就传入要监测的数据
                  (1).对象中 后追加的属性 Vue默认不做响应式处理
                  (2).如需给 后添加的属性做响应式 请使用如下API:
                            Vue.set(目标对象,属性名/索引,值)
                            vm.$set(目标对象,属性名/索引,值)
    3.如何监测数组中的数据?
                通过包裹数组更新元素的方法实现 本质就是做了两件事:
                  (1).调用原生对应的数组方法对数组进行更新
                  (2).重新解析模版 进行更新页面
    4.在Vue修改数组中的某一个元素一定要用如下方法:
           1.push()/pop()/shift()/unshift()/splice()sort()reverse()
           2.Vue.set/vm.$set()
        修改数组注意事项:
            (1).在纯数组数据结构中使用filter等不影响原元素的方法 会导致Vue监视不到 数据发生了更新 所以需要使用后重新赋值给调用者
            (2).数组里如有对象结构数据:数组索引是没有get、set的 但是数组里已配置的对象属性都是有的 所以可以直接 =赋值修改
            (3).纯数组(['只有字符串值'])是不可以通过索引直接赋值的 因为索引是没有get、set
    
    特别注意:Vue.set()/vm.$set 不能给vm 或 vm的根数据对象(data) 添加属性!
                             
 -->
    <div id="root">
        <h1>学生信息</h1>
        <button @click="student.age++">年龄+1岁</button><br>
        <button @click="addSex">添加性别属性 默认值男</button><br>
        <button @click="student.sex = '未知'">修改性别</button><br>
        <button @click="addFirstName">在列表首位添加一个朋友</button><br>
        <button @click="updateFirstName">在修改第一个朋友的名字为 张三</button><br>
        <button @click="addHobby">添加一个爱好</button><br>
        <button @click="updateFirstHobby">修改第一个爱好为 开车</button><br>
        <button @click="removSmoke('抽烟')">过滤爱好中的抽烟</button><br>

        <h2>姓名{{student.name}}</h2>
        <h2 v-if="student.sex">性别:{{student.sex}}</h2>

        <h2>年龄:{{student.age}}</h2>
        <br>

        <h1>朋友们</h1>
        <ul>
            <li v-for="(f,index) in student.frinends" :key="index">{{f.name}}-{{f.age}}</li>
        </ul>

        <h1>爱好</h1>
        <ul>
            <li v-for="(h,index) in student.hobby" :key="index">{{h}}</li>
        </ul>

    </div>
    <script>
        const vm = new Vue({
            el: '#root',
            data: {
                school: {
                    name: 'B站',
                    address: 'bbbbbb',
                },
                student: {
                    name: 'tom',
                    age: 20,
                    hobby:
                        //  h1:'抽烟',h2:'喝酒',h3:'烫头'
                        [
                            '抽烟', '喝酒', '烫头'
                        ],

                    frinends: [{
                        name: 'jerry',
                        age: 35
                    }
                    ]
                }
            },
            methods: {
                addSex() {
                    this.$set(this.student, 'sex', '男')
                },
                updateSex() {
                    Vue.set(this.student, 'sex', '女')
                },
                addFirstName() {
                    this.student.frinends.unshift({ name: 'tom', age: '40' })
                },
                updateFirstName() {
                    //数组索引是没有get、set的 但是数组里已配置的属性都有 所以可以直接修改
                    this.student.frinends[0].name = '张三'
                },
                addHobby() {
                    this.student.hobby.push('学习')
                },
                updateFirstHobby() {
                    // 纯数组(['只有字符串值'])是不可以通过索引直接赋值的 因为索引是没有get、set
                    // splice替换法
                    // this.student.hobby.splice(0, 1, '开车')
                    // Vue的另外两种方法
                    // Vue.set(this.student.hobby,0,'开车')
                    // this.$set(this.student.hobby,0,'开车')
                },
                removSmoke() {
                    // 因为Vue只有监测到数据发生变化后才会进行 一系列的 新旧虚拟dom对比在最后渲染真实dom 如果操作元素后因方法的特性不会改变原元素 那么就导致Vue无法监听到这次修改 也就无法响应回页面 
                    // Vue中修改纯数组 使用不影响原数组的数组方法时 需ruturn把处理后的结果 重新赋值给调用者
                    this.student.hobby = this.student.hobby.filter((h) => {
                        return h !== '抽烟'
                    })
                }

            }
        })
    </script>
</body>

</html>